<template>
  <div v-if="isDEV"  class="getControlTarAndPos" @click="getControlTarAndPos">获取视角</div>
  <div id="wrapper-canvas" ref="wrapperDom" class="wrapper">
    <a-spin :spinning="spinning" :tip="loadPercent" style="width: 100%">
      <canvas ref="canvas" class="three-canvas"></canvas>
    </a-spin>
  </div>
</template>
<script setup>
import NProgress from '@/plugins/nprogress'
import { PerspectiveCamera, Scene, WebGLRenderer } from 'three'
import { MODEL_PATH, PUBLIC_PATH, startFrom } from '@/views/technology/ZuTai/threejsUtil/config.js'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { addLight } from '@/views/technology/ZuTai/threejsUtil/utils.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import { ref, onMounted, toRefs, onBeforeUnmount } from 'vue'
import {
  waterFlowLineConfig,
  waterSurfaceConfig
} from '@/views/technology/ZuTai/modelConfig/config.js'
import gsap from 'gsap'
import * as THREE from 'three'
import { Water } from 'three/examples/jsm/objects/Water.js'
import WATER_NORMALS_JPG from '@/views/Technology/ZuTai/textures/waternormals.jpg'
import { isDEV } from '@/views/HomePage/modelCanvas/threejsUtil/config.js'

let gltfLoader = null
let scene = null
let camera = null
let renderer = null
let controls = null
let gltfScene = null
let requestAnimationFrameTimer = null
const canvas = ref(null)
const loadPercent = ref(0)
const wrapperDom = ref(null)
const spinning = ref(true)
let waterNormalsTexture = null // 水的法线贴图
// let sharedWaterMaterial = {}
/* 获取canvas的宽高*/
const props = defineProps({
  width: {
    type: Number,
    default: 0
  },
  height: {
    type: Number,
    default: 0
  }
})
const { width, height } = toRefs(props)
// 获取dom元素
const getWidthAndHeight = () => {
  return {
    width: width.value || wrapperDom.value.clientWidth,
    height: height.value || wrapperDom.value.clientHeight
  }
}
/*初始化*/
const init = async () => {
  const { width, height } = getWidthAndHeight()
  scene = new Scene()
  camera = new PerspectiveCamera(45, width / height, 0.1, 10000)
  camera.position.copy({
    x: startFrom.px,
    y: startFrom.py,
    z: startFrom.pz
  })
  renderer = new WebGLRenderer({
    canvas: canvas.value,
    antialias: true,
    alpha: true
  })
  renderer.setSize(width, height, false)
  controls = new OrbitControls(camera, renderer.domElement)
  controls.target.copy({
    x: startFrom.tx,
    y: startFrom.ty,
    z: startFrom.tz
  })
  controls.update()
  // 旋转角度 不让相机转到地面
  controls.minPolarAngle = -Math.PI / 2
  controls.maxPolarAngle = (Math.PI / 2) * 0.9
  const gltf = await loadGltf(`zuTaiAll.glb`)
  gltfScene = gltf.scene
  // 模型旋转
  // gltfScene.rotation.y = Math.PI
  // gltfScene.position.set(0, 10, 0)
  // scene.add(Helper)
  scene.add(gltfScene)
  addTexture()
  addLight(scene, renderer) //添加灯光
  waterFlow()
  pumpFlow()
  await loadWaterNormals()
  waterSurfaceFlow()
  console.log('初始化完成')
  spinning.value = false
  requestAnimationFrameTimer = requestAnimationFrame(render) //   渲染循环
}
/*EDN*/
const waterArrow = []
/*
 *   加载水面法线贴图
 * */
const loadWaterNormals = () => {
  return new Promise((resolve) => {
    if (waterNormalsTexture) {
      resolve(waterNormalsTexture)
    } else {
      new THREE.TextureLoader().load(WATER_NORMALS_JPG, (texture) => {
        texture.wrapS = texture.wrapT = THREE.RepeatWrapping
        waterNormalsTexture = texture
        resolve(texture)
      })
    }
  })
}
const addWater = async (existingPlane, name) => {
  let sharedWaterMaterial = {
    textureWidth: 125,
    textureHeight: 125, // 纹理的尺寸
    waterNormals: waterNormalsTexture, // 法线贴图
    sunDirection: new THREE.Vector3(), // 太阳的方向
    sunColor: 0xff0000, // 太阳的颜色
    waterColor: '#08bcff', // 水的颜色
    distortionScale: 2, // 失真的程度
    fog: scene.fog !== undefined // 是否使用雾效果
  }
  existingPlane.visible = false
  const water = new Water(existingPlane.geometry, sharedWaterMaterial)
  water.material.uniforms.size.value = 10
  water.rotation.copy(existingPlane.rotation)
  water.scale.copy(existingPlane.scale)
  water.position.copy(existingPlane.position)
  waterArrow.push(water)
  water.renderOrder = 1
  gltfScene.add(water)
}
/*END 加载水面法线贴图*/
/*
 * 给模型地面添加纹理
 * */
const addTexture = () => {}
/*
 * 水流动起来
 * */
const waterFlow = () => {
  waterFlowLineConfig.forEach((item) => {
    const water = gltfScene.getObjectByName(item.name)
    if (!water) return
    const texture = water.material.map
    gsap.to(texture.offset, {
      duration: item.duration,
      x: item.offset.x || 0,
      y: item.offset.y || 0,
      repeat: -1,
      ease: 'linear',
      onComplete: () => {}
    })
    texture.wrapS = THREE.RepeatWrapping
    texture.wrapT = THREE.RepeatWrapping
  })
}
/*
 * 水面动起来
 * */
const waterSurfaceFlow = () => {
  waterSurfaceConfig.forEach((item) => {
    let waterSurface = gltfScene.getObjectByName(item.name)
    if (!waterSurface) return
    const hheight = Math.random() * 3
    // 修改高度
    {
      // 最高 最低  最高就是 3m
      const heightRange = item.maxHeight - item.minHeight
      waterSurface.position.y = (heightRange / 3) * hheight + item.minHeight
    }
    {
      if (item.name === '平面006') {
        let xScale = 11.184 - 9.624
        let zScale = 12.085 - 11.125
        waterSurface.scale.set(
          (xScale / 3) * hheight + 9.624,
          waterSurface.scale.y,
          (zScale / 3) * hheight + 11.065
        )
      }
    }
    if (item.isStart) {
      addWater(waterSurface, item.name)
      return
    }
    let texture = waterSurface.material.map
    gsap.to(texture.offset, {
      duration: item.duration,
      ...item.offset,
      repeat: -1,
      ease: 'linear',
      onComplete: () => {}
    })
    //   设置纹理的wrap模式
    texture.wrapS = THREE.RepeatWrapping
    texture.wrapT = THREE.RepeatWrapping
  })
}
/*
 * 泵的涡轮转起来
 * */
const pumpFlow = () => {
  // 泵的涡轮
  const pump = gltfScene.getObjectByName('叶轮-岳化1#泵010')
  if (pump) {
    // 修改颜色
    pump.material.color.set(0x33ffff)
    gsap.to(pump.rotation, {
      duration: 1,
      z: Math.PI,
      repeat: -1,
      // 匀速
      ease: 'linear',
      onComplete: () => {
        //   修改颜色
        pump.material.color.set(0x00ff00)
      }
    })
  }
}
/* 加载模型*/
const loadGltf = (modelName) => {
  if (!gltfLoader) {
    gltfLoader = new GLTFLoader()
    const dracoLoader = new DRACOLoader()
    dracoLoader.setDecoderPath(`${PUBLIC_PATH}draco/`)
    gltfLoader.setDRACOLoader(dracoLoader)
  }
  return new Promise((resolve, reject) => {
    gltfLoader.load(
      `${MODEL_PATH}${modelName}`,
      (gltf) => resolve(gltf),
      ({ loaded, total }) => {
        loadPercent.value = Math.floor((loaded / total) * 100)
        NProgress.inc(loaded / total)
        if (loaded === total) {
          NProgress.done(true)
          loadPercent.value = '文件下载完成，解析中...'
          console.log('文件下载完成，解析中...')
        }
      },
      reject
    )
  })
}
// 销毁函数优化
const destroy = () => {
  try {
    // 取消动画帧请求
    cancelAnimationFrame(requestAnimationFrameTimer)

    // 清除所有 gsap 动画
    gsap.globalTimeline.clear()

    // 释放渲染器资源
    renderer.dispose()
    renderer.forceContextLoss()
    renderer.domElement = null

    // 遍历场景释放资源
    scene.traverse((object) => {
      if (object.isMesh) {
        if (object.geometry) {
          object.geometry.dispose()
        }
        if (object.material) {
          if (Array.isArray(object.material)) {
            object.material.forEach((mat) => {
              if (mat.map) mat.map.dispose()
              mat.dispose()
            })
          } else {
            if (object.material.map) object.material.map.dispose()
            object.material.dispose()
          }
        }
      }
    })

    // 销毁控制器
    if (controls) {
      controls.dispose()
    }

    // 销毁加载器
    if (gltfLoader) {
      gltfLoader.manager = null
      gltfLoader = null
    }

    // 重置所有变量
    camera = null
    scene = null
    gltfScene = null
  } catch (e) {
    console.error('Free Three Error:', e)
  }
}

/*
 * 渲染循环
 * */
function render() {
  requestAnimationFrameTimer = requestAnimationFrame(render)
  renderer.render(scene, camera)
  waterArrow.forEach((item) => {
    item.material.uniforms['time'].value += .5 / 60
    item.material.uniformsNeedUpdate = true
  })
  if (resizeRendererToDisplaySize(renderer)) {
    camera.aspect = wrapperDom.value?.clientWidth / wrapperDom.value?.clientHeight
    camera.updateProjectionMatrix()
  }
}

// 重置相机
function resizeRendererToDisplaySize(renderer) {
  const canvas = renderer.domElement
  const width = canvas.clientWidth
  const height = canvas.clientHeight
  const needResize = canvas.width !== width || canvas.height !== height
  if (needResize) {
    renderer.setSize(width, height, false)
  }
  return needResize
}

const onResize = () => {
  const { width, height } = getWidthAndHeight()
  camera.aspect = width / height
  camera.updateProjectionMatrix()
  renderer.setSize(width, height, false)
}
/** 开发相关 获取 */
const getControlTarAndPos = (print = true) => {
  // back()
  const target = controls.target
  const position = controls.object.position
  const targetS = JSON.stringify(target)
  const positionS = JSON.stringify(position)
  if (print) {
    const getStyle = (color = '#f00') => `padding: 2px 4px; color: #ffffff; background: ${color};`
    console.log(`%ctarget: ${targetS}`, getStyle())
    console.log(`%cposition: ${positionS}`, getStyle('#049F70FF'))
  }
  return { target, position }
}
// 初始化
onMounted(async () => {
  document.body.classList.add('threejs-body')
  await loadWaterNormals()
  await init()
  window.addEventListener('resize', onResize)
})
// 销毁
onBeforeUnmount(() => {
  document.body.classList.remove('threejs-body')
  destroy()
  window.removeEventListener('resize', onResize)
})
</script>

<style lang="scss" scoped>
.three-canvas {
  width: 100%;
  height: 100%;
  overflow: hidden;
  clear: both;
}

.wrapper {
  width: calc(100vw);
  height: calc(100vh);
  position: absolute;
}

.getControlTarAndPos {
  position: absolute;
  top: 30px;
  z-index: 11;
  right: 30px;
}
</style>
